package org.opens.javaskill.design.apply;

/**
 * 功能:
 * <p>典型的共享资源竞争问题: 只有一个门, 以此只允许一个人过</p>
 * 说明:
 * <pre>
 *     1. 在这个模型中, 门(gate)就是共享资源, 人是消耗资源的对象也称为临界资源;
 * </pre>
 * @Date 2020/9/2 20:57
 * @Created by 99126
 */
public class SingleThreadDemo {

    public static void main(String[] args) {
        Gate gate = new Gate();
        User user1 = new User("baobao", "beijing", gate);
        User user2 = new User("guangtouqiang", "guangzhou", gate);
        User user3 = new User("shanshan", "shanxi", gate);

        user1.start();
        user2.start();
        user3.start();
    }

}

/**
 * 说明:
 * <p>这是共享资源-门抽象出的类</p>
 */
class Gate {

    private int counter = 0;

    private String name = "nobody";

    private String address = "nowhere";

    public void pass(String name, String address) {
        this.name = name;
        this.address = address;
        this.counter++;
        verify();
    }

    public void verify() {
        /*
        说明:
            1. 如果对比的name和address的首字母不同, 则打印.
         */
        if ( this.name.charAt(0) != this.address.charAt(0) ) {
            System.out.println("***broken***" + this);
        }
    }

    @Override
    public String toString() {
        return "Gate{" +
                "counter=" + counter +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

}

/**
 * 说明:
 * <p>这是人抽象出的类</p>
 */
class User extends Thread {

    private String myName;

    private String myAddress;

    private final Gate gate;

    public User(String myName, String myAddress, Gate gate) {
        this.myName = myName;
        this.myAddress = myAddress;
        this.gate = gate;
    }

    @Override
    public void run() {
        System.out.println(myName + " begin access the gate");
        while (true) {
            /*
            说明:
                1. 这里如果不加同步就会出现临界资源不同步的问题: A线程使用本身的数据进行比较时, B线程又修改了临界资源, 导致数据对比结果无效,
                可以去掉这个锁观察效果.
             */
            synchronized (gate) {
                this.gate.pass(myName, myAddress);
            }
        }
    }

}